package com.milhouz.bomberrokon.util;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import android.app.Activity;
import android.util.Log;

import com.milhouz.bomberrokon.model.MapModel;
import com.milhouz.bomberrokon.model.PlayerMapModel;
import com.milhouz.bomberrokon.model.Tile;
import com.milhouz.bomberrokon.model.TileData;
import com.stickycoding.Rokon.Rokon;

public class MapXmlReader {

	public static final String ASSETS_MAP_FOLDER = "maps";
	public static final String THUMB_FILENAME = "thumb.png";
	public static final String XML_MAP_FILENAME = "map.xml";
	private final String TILE_SEPARATOR = ",";

	private String mapCode;
	private MapModel mapModel;
	private int indexTileY = 0;
	private int indexPlayer = 0;

	public MapXmlReader(String mapCode, MapModel mapModel) {
		this.mapCode = mapCode;
		this.mapModel = mapModel;
		mapModel.setMapCode(mapCode);
	}

	public void parse() {
		InputStream mapInputStream = null;
		SAXParserFactory spf = SAXParserFactory.newInstance();
		try {
			SAXParser sp = spf.newSAXParser();
			XMLReader xr = sp.getXMLReader();
			xr.setContentHandler(new DefaultHandler() {

				@Override
				public void startDocument() throws SAXException {
					super.startDocument();
				}

				@Override
				public void startElement(String uri, String localName, String name, Attributes atts) throws SAXException {
					super.startElement(uri, localName, name, atts);
					if (localName.equalsIgnoreCase("map")) {
						mapModel.setMapName(atts.getValue("name"));
						String background = atts.getValue("background");
						if (background != null) {
							if (background.contains(",")) {
								mapModel.setBackgroundColor(atts.getValue("background"));
							} else {
								mapModel.setBackgroundFile(atts.getValue("background"));
							}
						}
					} else if (localName.equalsIgnoreCase("players")) {
						mapModel.setMaxPlayers(Integer.parseInt(atts.getValue("max")));
					} else if (localName.equalsIgnoreCase("player")) {
						mapModel.getPlayersPos()[indexPlayer] = new PlayerMapModel(Integer.parseInt(atts.getValue("id")) //
								, Integer.parseInt(atts.getValue("posX"))//
								, Integer.parseInt(atts.getValue("posY")));
						indexPlayer++;
					} else if (localName.equalsIgnoreCase("item")) {
						if (atts.getValue("name").equalsIgnoreCase("flam")) {
							mapModel.getItems().setNbFlamItems(Integer.parseInt(atts.getValue("number")));
						} else if (atts.getValue("name").equalsIgnoreCase("bomb")) {
							mapModel.getItems().setNbBombItems(Integer.parseInt(atts.getValue("number")));
						} else if (atts.getValue("name").equalsIgnoreCase("speed")) {
							mapModel.getItems().setNbSpeedItems(Integer.parseInt(atts.getValue("number")));
						}
					} else if (localName.equalsIgnoreCase("textures")) {
						mapModel.setExploseWallFile(atts.getValue("explose"));
						mapModel.setExploseWallNbTiles(Integer.valueOf(atts.getValue("exploseTiles")));
					} else if (localName.equalsIgnoreCase("texture")) {
						TileData tiledata = null;
						if (Boolean.valueOf(atts.getValue("destructable"))) {
							tiledata = new TileData(atts.getValue("name") //
									, Boolean.valueOf(atts.getValue("destructable")) //
									, atts.getValue("explose") //
									, Integer.valueOf(atts.getValue("exploseTiles")) //
									, Integer.valueOf(atts.getValue("exploseFrameRate")));
						} else {
							tiledata = new TileData(atts.getValue("name"), Boolean.valueOf(atts.getValue("destructable")));
						}
						mapModel.getTileData().put(Integer.parseInt(atts.getValue("id")), tiledata);
					} else if (localName.equalsIgnoreCase("tiles")) {
						mapModel.setNbTileWidth(Integer.parseInt(atts.getValue("width")));
						mapModel.setNbTileHeight(Integer.parseInt(atts.getValue("height")));
						mapModel.setTileSize(Integer.parseInt(atts.getValue("tileSize")));
						mapModel.initMapTiles();
					} else if (localName.equalsIgnoreCase("row")) {
						mapModel.getMapTiles()[indexTileY] = parseTileRow(atts.getValue("value"));
						indexTileY++;
					}
				}

				@Override
				public void endElement(String uri, String localName, String name) throws SAXException {
					super.endElement(uri, localName, name);
					if (localName.equalsIgnoreCase("map")) {
						mapModel.countNbDisplayableObjects();
					}
				}

				@Override
				public void characters(char[] ch, int start, int length) throws SAXException {
					super.characters(ch, start, length);
				}

			});
			mapInputStream = Rokon.getRokon().getActivity().getAssets().open(ASSETS_MAP_FOLDER + "/" + mapCode + "/" + XML_MAP_FILENAME);
			xr.parse(new InputSource(mapInputStream));
		} catch (Exception e) {
			Log.e("bomberman", "SAX parsing failed", e);
		} finally {
			try {
				if (mapInputStream != null) {
					mapInputStream.close();
				}
			} catch (IOException e) {
				Log.e("bomberman", "Impossible to close XML map input stream : " + mapCode, e);
			}
		}
	}

	private Tile[] parseTileRow(String tileRow) {
		String[] splitedTiles = tileRow.split(TILE_SEPARATOR);
		Tile[] tiles = new Tile[splitedTiles.length];
		for (int x = 0; x < splitedTiles.length; x++) {
			tiles[x] = new Tile(x //
					, indexTileY //
					, x * mapModel.getTileSize() + mapModel.getOriginMapX() //
					, indexTileY * mapModel.getTileSize() + mapModel.getOriginMapY() //
					, mapModel.getTileSize() //
					, Integer.parseInt(splitedTiles[x].trim()));
		}
		return tiles;
	}

	public static MapModel getMapSettings(Activity activity, String mapCode) {
		final MapModel mapModel = new MapModel(mapCode);
		InputStream mapInputStream = null;
		SAXParserFactory spf = SAXParserFactory.newInstance();
		try {
			SAXParser sp = spf.newSAXParser();
			XMLReader xr = sp.getXMLReader();
			xr.setContentHandler(new DefaultHandler() {
				@Override
				public void startElement(String uri, String localName, String name, Attributes atts) throws SAXException {
					super.startElement(uri, localName, name, atts);
					if (localName.equalsIgnoreCase("map")) {
						mapModel.setMapName(atts.getValue("name"));
					} else if (localName.equalsIgnoreCase("players")) {
						mapModel.setMaxPlayers(Integer.parseInt(atts.getValue("max")));
					} else if (localName.equalsIgnoreCase("tiles")) {
						mapModel.setNbTileWidth(Integer.parseInt(atts.getValue("width")));
						mapModel.setNbTileHeight(Integer.parseInt(atts.getValue("height")));
						mapModel.setTileSize(Integer.parseInt(atts.getValue("tileSize")));
					}
				}
			});
			mapInputStream = activity.getAssets().open(ASSETS_MAP_FOLDER + "/" + mapCode + "/" + XML_MAP_FILENAME);
			xr.parse(new InputSource(mapInputStream));
		} catch (Exception e) {
			Log.e("bomber", "SAX parsing failed", e);
		} finally {
			try {
				if (mapInputStream != null) {
					mapInputStream.close();
				}
			} catch (IOException e) {
				Log.e("bomberman", "Impossible to close XML map input stream : " + mapCode, e);
			}
		}
		return mapModel;
	}
}
